home *** CD-ROM | disk | FTP | other *** search
- unit Sorts; {John Haluska CIS 74000,1106} {Turbo Pascal 5.0, 5.5}
-
- {$A+,B-,D+,E-,F-,I+,L+,N-,R-,S-,V-}
-
- { Ver 1.0 9/22/90 Released to the public domain }
-
- { Sorts contains a general purpose engine to sort in-memory static or dynamic
- (heap) arrays of any type using the QuickSort algorithm. The user must
- define a compare function for the sort criteria. Then call the sort
- procedure with the array address, sort range (first/last elements), number
- of bytes in each element, and compare function name. Refer to examples at
- the end of this unit for typical use. }
-
- interface
-
- type
- CmpTyp = function(var X1,X2) : boolean; {define sort order criteria}
-
- procedure SwapBytes(var A,B; Len : word);
- procedure QSort(var A; Ef,El,Es : integer; F : CmpTyp);
-
- implementation
-
- {----------------------------------------------------------------------------}
- { SwapBytes exchanges untyped variables A and B. Len specifies the number of
- bytes in A or B. Both A and B must contain the same number of bytes.
- Example: SwapBytes(A,B,SizeOf(A)) exchanges A and B. }
-
- procedure SwapBytes(var A,B; Len : word);
-
- begin
- inline(
- $8C/$DA/ { MOV DX,DS ;Save DS in DX }
- $8B/$8E/>Len/ { MOV CX,>Len[BP] ;Copy Len to CX }
- $E3/$13/ { JCXZ X1 ;Quit if Len = 0 }
- $C5/$B6/>A/ { LDS SI,>A[BP] ;Load A addr }
- $C4/$BE/>B/ { LES DI,>B[BP] ;Load B addr }
- $FC/ { CLD ;Set string ops to forward }
- $8A/$04/ {X2: MOV AL,[SI] ;Read A }
- $8A/$25/ { MOV AH,[DI] ;Read B }
- $88/$24/ { MOV [SI],AH ;Write A in B addr }
- $AA/ { STOSB ;Write B in A addr, incr B addr}
- $46/ { INC SI ;Increment A addr }
- $E2/$F6/ { LOOP X2 ;Repeat }
- $8E/$DA) {X1: MOV DS,DX ;Restore DS }
- end; {SwapBytes}
- {----------------------------------------------------------------------------}
- { QSort sorts, using the Quicksort algorithm, items in A, the address of an
- in-memory static or dynamic (heap) array from start element Ef to last
- element El according to user supplied compare function F. Es is the number
- of bytes in each array element. F is Comp(var X1,X2) : boolean. The array
- will sort in ascending order if X1 < X2 and Comp returns true. The array
- index must start at 0. The Turbo Pascal structure limit requires that
- (El+1)*Es <= 65521 bytes. Consequently up to 32760 words/integers or 16380
- pointers/long integers can be sorted. For static arrays, a pointer variable
- must be used to provide the array address. }
-
- procedure QSort(var A; Ef,El,Es : integer; F : CmpTyp);
-
- type
- BufType = array[0..0] of byte; {abstract zero based array structure}
- var
- Buf : ^BufType absolute A; {Buf at same addr as A}
- Pivot : ^BufType;
- {--------}
- procedure Sort(L,R : integer);
- var
- I,J : word;
- begin
- I := L;
- J := R;
- Move(Buf^[((I+J) shr 1)*Es],Pivot^,Es); {get pivot value from mid list}
- repeat
- while F(Buf^[I*Es],Pivot^) do Inc(I); {compare}
- while F(Pivot^,Buf^[J*Es]) do Dec(J); {compare}
- if integer(I) <= integer(J) then
- begin
- SwapBytes(Buf^[I*Es],Buf^[J*Es],Es);
- Inc(I);
- Dec(J)
- end;
- until integer(I) > integer(J);
- if integer(L) < integer(J) then Sort(L,J);
- if integer(I) < integer(R) then Sort(I,R)
- end;
- {-------}
- begin
- GetMem(Pivot,Es); {allocate pivot buffer}
- {$S+} Sort(Ef,El); {$S-} {sort with stack overflow checking}
- FreeMem(Pivot,Es) {deallocate pivot buffer}
- end; {QSort}
- {----------------------------------------------------------------------------}
- end.
- (*
- { Example 1: Sort static array of integers in ascending order.}
-
- var
- L1 : array[0..100] of integer; {must start at 0, max size = 32760}
- L1Ptr : pointer;
- I : integer;
-
- {$F+} function Comp1(var X1,X2) : boolean; {user supplied, far call}
- begin
- if integer(X1) < integer(X2) then Comp1 := true {note reqd typecast}
- else Comp1 := false
- end; {$F-}
-
- begin
- L1[1] := 5; L1[2] := 3; L1[3] := 1;
- L1Ptr := @L1; {address of L1}
- QSort(L1Ptr,1,3,SizeOf(integer),Comp1);
- for I := 1 to 3 do Write(L1[I],' ');
- Writeln
- end.
- {---------}
- { Example 2: Sort dynamic array of integers in descending order.}
-
- type
- ArrayTyp = array[0..32759] of integer; {must start at 0, max size = 32760}
- L2Typ = ^ArrayTyp;
- var
- L2 : L2Typ;
- I : integer;
-
- {$F+} function Comp2(var X1,X2) : boolean; {user supplied, far call}
- begin
- if integer(X1) > integer(X2) then Comp2 := true {note reqd typecast}
- else Comp2 := false
- end; {$F-}
-
- begin
- GetMem(L2,3*SizeOf(integer)); {allocate heap memory}
- L2^[0] := 5; L2^[1] := 1; L2^[2] := 3;
- QSort(L2,0,2,SizeOf(integer),Comp2);
- for I := 0 to 2 do Write(L2^[I],' ');
- Writeln;
- FreeMem(L2,3*SizeOf(integer)) {deallocate heap memory}
- end.
- {----------}
- { Example 3: Sort static array of pointers to records, according to Name, in
- ascending order. }
-
- type
- IdRec = record
- Id : integer;
- Name : string[20];
- end;
- IdRecPtr = ^IdRec;
- var
- L3 : array[0..100] of ^IdRec; {structure = 101*23, must start at 0}
- L3Ptr : pointer; {address of static array}
- I : integer;
-
- {$F+} function Comp3(var X1,X2) : boolean; {user supplied, far call}
- begin {note type cast}
- if IdRecPtr(X1)^.Name < IdRecPtr(X2)^.Name then Comp3 := true
- else Comp3 := false
- end; {$F-}
-
- begin
- New(L3[0]); {must allocate record 0, even if not used}
- New(L3[1]); L3[1]^.Name := 'James';
- New(L3[2]); L3[2]^.Name := 'Bill';
- New(L3[3]); L3[3]^.Name := 'Tom';
- L3Ptr := @L3; {addr of L3}
- QSort(L3Ptr,1,3,SizeOf(L3[I]),Comp3);
- for I := 1 to 3 do Write(L3[I]^.Name,' ');
- Writeln
- end.
- {----------}
- { Example 4: Sort static array of pointers to records, by last and first
- name in ascending order, using dynamic integer array as index. }
-
- type
- NmRec = record
- NameF : string[20];
- NameL : string[20];
- end;
- NmLst = array[1..2000] of ^NmRec; {structure = 4*2000}
- Int = array[0..2000] of integer; {sort array index, must start at 0}
- var
- L4 : NmLst; {static array of pointers to NmRec}
- L5 : ^Int; {pointer to dynamic array of integers}
- I,LstLen : integer;
-
- {$F+} function Comp4(var X1,X2) : boolean; {user supplied, far call}
- begin
- if L4[integer(X1)]^.NameL < L4[integer(X2)]^.NameL then {note typecast}
- Comp4 := true
- else
- if (L4[integer(X1)]^.NameL = L4[integer(X2)]^.NameL) and
- (L4[integer(X1)]^.NameF < L4[integer(X2)]^.NameF) then
- Comp4 := true
- else
- Comp4 := false
- end; {$F-}
-
- begin
- New(L4[1]); L4[1]^.NameL := 'Smith'; L4[1]^.NameF := 'John';
- New(L4[2]); L4[2]^.NameL := 'Smith'; L4[2]^.NameF := 'Jack';
- New(L4[3]); L4[3]^.NameL := 'Small'; L4[3]^.NameF := 'Joe';
- New(L4[4]); L4[4]^.NameL := 'Small'; L4[4]^.NameF := 'John';
- LstLen := 4;
- GetMem(L5,(LstLen+1)*SizeOf(integer)); {must include element 0}
- for I := 1 to LstLen do L5^[I] := I; {initialize index array}
- QSort(L5,1,LstLen,SizeOf(integer),Comp4);
- for I := 1 to LstLen do
- Writeln(L4[L5^[I]]^.NameL,' ',L4[L5^[I]]^.NameF);
- Writeln;
- FreeMem(L5,(LstLen+1)*SizeOf(integer));
- for I := 1 to LstLen do Dispose(L4[I]);
- end.
- *)